package paim.gh.controller;


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.List;
import java.util.Objects;
import java.util.Vector;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JSpinner;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import paim.wingchun.controller.HasConstrutor;
import paim.wingchun.controller.Selecionar;
import paim.wingchun.controller.WC_Event;
import paim.wingchun.controller.eventos.DefaultConstrutorEvent;
import paim.wingchun.controller.eventos.DevolucaoEvent;
import paim.wingchun.model.pojos.Pojo;

import paim.gh.model.modelos.SemestreModel;
import paim.gh.model.pojos.Curso;
import paim.gh.model.pojos.Disciplina;
import paim.gh.model.pojos.Semestre;
import paim.gh.view.DisciplinaView;

import static paim.wingchun.app.Reflections.getValorField;
import static paim.wingchun.app.WC_Strings.formataLista;

/** @author paim 05/05/2011 */
public class DisciplinaController extends AbstractTabelaController<Disciplina, DisciplinaView> implements
                ChangeListener, MouseWheelListener, ActionListener, HasConstrutor {

    public DisciplinaController() {
        super();
    }

    @Override
    protected boolean antes_populaVisao() throws Exception {
        /* popula combo semestre */
        Vector<Pojo> lista = new Vector<Pojo>(SemestreModel.getInstance().list(getSessao()));
        ComboBoxModel<Pojo> model = new DefaultComboBoxModel<Pojo>(lista);
        getVisao().getJSemestre().setModel(model);
        return super.antes_populaVisao();
    }

    @Override
    protected void apos_addListeners() {
        super.apos_addListeners();
        getVisao().getnPeriodos().addChangeListener(this);
        getVisao().getnPeriodos().addMouseWheelListener(this);
        /* adicionando listener somente na parte Texto do jspinner */
        ((JSpinner.DefaultEditor) getVisao().getnPeriodos().getEditor()).getTextField().addFocusListener(this);

        getVisao().getJBConstrutor().addActionListener(new DefaultConstrutorEvent() {

            @Override
            public void constroi() {
                new Selecionar<Curso>(DisciplinaController.this, (Disciplina) getObjeto(), getVisao().getJCurso(),
                                Curso.class);
            }
        });
        // getVisao().getJCurso().addActionListener(this);
        getVisao().getJSemestre().addActionListener(this);
    }

    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {
        /* verifica se nao esta parado */
        if ( !canDisparaEvento() )
            return;

        if ( !(e.getSource() instanceof JSpinner) )
            return;
        JSpinner componente = (JSpinner) e.getSource();

        if ( e.getWheelRotation() < 0 ) {
            /* se for null, eh por que ultrapasou a escala, entao nao faz nada */
            if ( componente.getNextValue() != null )
                componente.setValue(componente.getNextValue());
        }
        else {
            /* se for null, eh por que ultrapasou a escala, entao nao faz nada */
            if ( componente.getPreviousValue() != null )
                componente.setValue(componente.getPreviousValue());
        }
    }

    @Override
    public void stateChanged(ChangeEvent e) {
        /* verifica se nao esta parado */
        if ( !canDisparaEvento() )
            return;

        if ( !(e.getSource() instanceof JSpinner) )
            return;

        Object valorNovo = null;
        Object valorAntigo = null;

        JSpinner componente = (JSpinner) e.getSource();
        valorNovo = componente.getModel().getValue();

        Disciplina pojo = (Disciplina) getVisao().getObjetoReferencia();

        if ( getVisao().getnPeriodos().equals(componente) ) {
            valorAntigo = pojo.getNumPeriodos();
            if ( Objects.equals(valorAntigo, valorNovo) )
                return;
            /* altera no objeto */
            pojo.setNumPeriodos((Integer) valorNovo);
            /* notifica mudanca */
            fire(new WC_Event(Eventos.ALTERANDO, pojo, valorAntigo, valorNovo, e, componente));
        }
        else
            /* se nao for outro componente cai fora */
            return;
    }

    @Override
    public void recebeObjeto(Object objeto, JComponent component) throws Exception {
        Object valorNovo = null;
        Object valorAntigo = null;
        Disciplina pojo = (Disciplina) getVisao().getObjetoReferencia();

        if ( getVisao().getJCurso().equals(component) ) {
            valorAntigo = pojo.getCursos();
            valorNovo = (objeto == null ? null : objeto);

            /* coloco o objeto retornado no componente */
            List<String> siglas = getValorField((List<Curso>) valorNovo, String.class, "sigla");
            getVisao().getJCurso().setText(formataLista(siglas));

            if ( Objects.equals(valorAntigo, valorNovo) )
                return;

            /* altera no objeto */
            pojo.setCursos((List<Curso>) valorNovo);
            /* notifica mudanca */
            DevolucaoEvent e = new DevolucaoEvent(component, DisciplinaController.class, Selecionar.class, Curso.class);
            fire(new WC_Event(Eventos.ALTERANDO, pojo, valorAntigo, valorNovo, e, component));
        }
        else
            return;

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if ( !canDisparaEvento() )
            return;

        if ( !(e.getSource() instanceof JComboBox) )
            return;

        Object valorNovo = null;
        Object valorAntigo = null;

        Disciplina pojo = (Disciplina) getVisao().getObjetoReferencia();

        JComboBox<?> componente = (JComboBox<?>) e.getSource();

        valorNovo = componente.getModel().getSelectedItem();

        if ( getVisao().getJSemestre().equals(componente) ) {
            valorAntigo = pojo.getSemestre();
            if ( Objects.equals(valorAntigo, valorNovo) )
                return;
            /* altera no objeto */
            pojo.setSemestre((Semestre) valorNovo);
            /* notifica mudanca */
            fire(new WC_Event(Eventos.ALTERANDO, pojo, valorAntigo, valorNovo, e, componente));
        }

        else
            /* se nao for outro componente cai fora */
            return;

    }
}
